#region Using

using System;
using System.Collections.Generic;

#endregion

namespace BlogEngine.Core
{
	/// <summary>
	/// Categories are a way to organize posts. 
	/// A post can be in multiple categories.
	/// </summary>
	[Serializable]
	public class Category : BlogBase<Category>, IComparable<Category>
	{

		#region Constructor

		/// <summary>
		/// Initializes a new instance of the <see cref="Category"/> class.
		/// </summary>
		public Category()
			: base()
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="title"></param>
		/// <param name="slug"></param>
		/// <param name="description"></param>
		public Category(string title, string slug, string description)
		{
			this.Id = Guid.NewGuid();
			this.Title = title;
			this.Slug = string.IsNullOrEmpty(slug) ? Utils.RemoveIllegalCharacters(title) : Utils.RemoveIllegalCharacters(slug);
			this.Description = description;
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="title"></param>
		/// <param name="slug"></param>
		/// <param name="description"></param>
		/// <param name="parent"></param>
		public Category(string title, string slug, string description, Category parent)
			: this(title, slug, description)
		{
			this._Parent = parent.Id;
		}

		public Category(string title, string description)
		{
			this.Id = Guid.NewGuid();
			this.Title = title;
			this.Description = description;
		}

		#endregion

		#region Properties


		private Guid _Parent;
		/// <summary>
		/// Gets or sets the parent of the Category. It is used to construct the 
		/// hierachy of the categories.
		/// </summary>
		public Guid Parent
		{
			get { return _Parent; }
			set
			{
				if (_Parent != value) MarkChanged("Parent");
				_Parent = value;
			}
		}

		/// <summary>
		/// Returns a collection of child category items for parent item provided
		/// </summary>
		/// <param name="parent"></param>
		/// <returns></returns>
		public static List<Category> GetChildCategories(Category parent)
		{
			return GetChildCategories(parent.Id);
		}

		/// <summary>
		/// Returns a collection of child category items for parent item provided
		/// </summary>
		/// <param name="parent"></param>
		/// <returns></returns>
		public static List<Category> GetChildCategories(Guid parentId)
		{
			List<Category> list = BlogBase<Category>.Items.FindAll(delegate(Category item)
			{
				return (item.Parent == parentId);
			});
			list.Sort();

			return list;
		}

		#endregion

		#region IComparable<Category> Members

		/// <summary>
		/// Compares the current object with another object of the same type.
		/// </summary>
		/// <param name="other">An object to compare with this object.</param>
		/// <returns>
		/// A 32-bit signed integer that indicates the relative order of the objects being compared. 
		/// The return value has the following meanings: Value Meaning Less than zero This object is 
		/// less than the other parameter.Zero This object is equal to other. Greater than zero This object is greater than other.
		/// </returns>
		public int CompareTo(Category other)
		{
			return CompareOrderAndTitle(this.Order, DateTime.MinValue, this.Title, other.Order, DateTime.MinValue, other.Title);
		}

		#endregion

		#region Data Access

		static internal BlogEngine.Core.Provider.Interfaces.ICategories CategoryProvider = BlogEngine.Core.Provider.BlogService.Provider.GetInterface<BlogEngine.Core.Provider.Interfaces.ICategories>();

		protected override void DataDelete()
		{
			//make sure any child categories have the parent removed
			foreach (Category child in Category.GetChildCategories(this))
			{
				child.Parent = Guid.Empty;
				child.Save();
			}

			//make sure any posts have the category set to the default posting category
			Guid defaultGuid = new Guid(BlogSettings.Instance.DefaultCategory);
			Category defaultCat = Category.GetById(defaultGuid);

			foreach (Post post in Post.GetByCategory(this.Id, false, false))
			{
				post.Categories.Remove(this);
				if (post.Categories.Count <= 0)
					post.Categories.Add(defaultCat);

				post.Save();
			}

			//make sure any links have the category removed 
			foreach (Link link in Link.GetByCategory(this.Id))
			{
				link.Categories.Remove(this);
				link.Save();
			}

			CategoryProvider.Delete(this);
		}

		protected override void DataInsert()
		{
			CategoryProvider.Insert(this);
		}

		protected override Category DataSelect(Guid id)
		{
			return CategoryProvider.Select(id);
		}

		protected override void DataUpdate()
		{
			CategoryProvider.Update(this);
		}

		private static int Dummy = OverrideOnLoad();

		private static int OverrideOnLoad()
		{
			OnLoad = CategoryProvider.Fill;
			return 0;
		}

		#endregion

		/// <summary>
		/// Gets the Categories.
		/// </summary>
		/// <value>The Categories.</value>
		public static List<Category> Categories
		{
			get
			{
				return Items;
			}
		}

		/// <summary>
		/// Returns a category based on the specified id.
		/// </summary>
		public static Category GetCategory(Guid id)
		{
			return GetById(id);
		}
	}
}
